//
//  FileCacheTest.cpp
//  GRE
//
//  Created by Kutlak Roman on 24/10/2011.
//  Copyright (c) 2011 University of Aberdeen. All rights reserved.
//
#include <string>
#include <sstream>
#include <fstream>
#include <cstdio>

#include "gtest/gtest.h"

#include "Cache.h"
using namespace std;
using namespace kutlak::roman::gre;

TEST(Cache, FileCacheConstructor) 
{
    Cache<string, string> c(100, "default");
    EXPECT_EQ(false, c.IsModified());
    EXPECT_EQ(string("default"), c.Find("key"));
    EXPECT_EQ(100, c.MaxSize());
    
    Cache<string, string> c2;
    EXPECT_EQ(false, c2.IsModified());
    EXPECT_EQ(string(), c2.Find("key1"));
    
    Cache<string, string> c3(100, "value");
    c3.Insert("key1", "value1");
    EXPECT_EQ(true, c3.IsModified());
    EXPECT_EQ(string("value1"), c3.Find("key1"));
    
}


TEST(FileCache, FileCacheConstructor) 
{
    try 
    {
        FileCache<string, string> c("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt");
        EXPECT_EQ(false, c.IsModified());
        EXPECT_EQ("default", c.Find("key"));
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, false);
        cerr << de.what() << endl;
    }
    
    try 
    {
        FileCache<string, string> c2("bad_path");
        EXPECT_EQ(true, false);
    } 
    catch (DeserialisationException& de) 
    {
        cerr << de.what() << endl;
    }
    
    try 
    {
        FileCache<string, string> c2("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile_faulty.txt");
        EXPECT_EQ(true, false);
    } 
    catch (DeserialisationException& de) 
    {
        cerr << de.what() << endl;
    }
    
    try 
    {
        FileCache<string, string> c3("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt");
        EXPECT_EQ(false, c3.IsModified());
        EXPECT_EQ("value1", c3.Find("key1"));
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, false);
        cerr << de.what() << endl;
    }
    
}

TEST(FileCache, FileCacheCopyCtor) 
{
    try 
    {
        FileCache<string, string> c("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt");
        EXPECT_EQ(false, c.IsModified());
        EXPECT_EQ("default", c.Find("key"));
        
        FileCache<string, string> c2(c);
        EXPECT_EQ(false, c2.IsModified());
        EXPECT_EQ("default", c2.Find("key"));
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, false);
        cerr << de.what() << endl;
    }
}

TEST(FileCache, Insert) 
{
    // cache with space for 2 entries
    Cache<string, string> c(2);
    EXPECT_EQ(0, c.Size());
    c.Insert("key1", "value1");
    EXPECT_EQ(1, c.Size());
    c.Insert("key2", "value2");
    EXPECT_EQ(2, c.Size());
    
    EXPECT_EQ("value1", c.Find("key1"));
    EXPECT_EQ("value2", c.Find("key2"));
    EXPECT_EQ("", c.Find("key3"));
    
    c.Insert("key3", "value3");
    EXPECT_EQ(2, c.Size());
    
    EXPECT_EQ("", c.Find("key1"));
    EXPECT_EQ("value2", c.Find("key2"));
    EXPECT_EQ("value3", c.Find("key3"));

}

TEST(FileCache, Find) 
{
    try 
    {
        FileCache<string, string> c("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt");
        EXPECT_EQ(false, c.IsModified());
        EXPECT_EQ("default", c.Find("key"));
        
        EXPECT_EQ("value1", c.Find("key1"));
        EXPECT_EQ("default", c.Find("key5"));
        c.Insert("key5", "value5");
        EXPECT_EQ(true, c.IsModified());
        EXPECT_EQ("value5", c.Find("key5"));
        
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, false);
        cerr << de.what() << endl;
    }
}

TEST(FileCache, SetFile) 
{
    string file("/tmp/cache.txt");
    
    // make sure all cache values are delete
    remove(file.c_str());
    
    try 
    {
        FileCache<string, string> c(file);
        EXPECT_EQ(false, c.IsModified());
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, true);
        cerr << de.what() << endl;
    }
    
    FileCache<string, string> c;
    c.SetFile("/tmp/cache.txt", false);
    
    EXPECT_EQ(string(), c.Find("key5"));
    c.Insert("key5", "value5");
    EXPECT_EQ(true, c.IsModified());
    EXPECT_EQ("value5", c.Find("key5"));
    c.Save();
    EXPECT_EQ(false, c.IsModified());
    EXPECT_EQ("value5", c.Find("key5"));
    c.Clear();
    EXPECT_EQ(true, c.IsModified());
    EXPECT_EQ(string(), c.Find("key5"));
    
    c.Insert("key5", "value5");
    EXPECT_EQ(true, c.IsModified());
    EXPECT_EQ("value5", c.Find("key5"));
    
    // this should fail but not affect the content
    c.SetFile("/tmp/badfile/cache.txt", true);
    EXPECT_EQ("value5", c.Find("key5"));
    
    c.SetFile("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt", true);
    EXPECT_EQ("value1", c.Find("key1"));
}

TEST(FileCache, Save) 
{
    string file("/tmp/cache.txt");
    
    // make sure all cache values are delete
    remove(file.c_str());
    FileCache<string, string>* c;
    
    try 
    {
        c = new FileCache<string, string>(file);
        EXPECT_EQ(false, c->IsModified());
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, true);
        cerr << de.what() << endl;
    }
    
    try 
    {
        c = new FileCache<string, string>();
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, false);
        cerr << de.what() << endl;
    }
    
    ASSERT_NE(nullptr, c);
    
    c->SetFile("/tmp/cache.txt", false);
    EXPECT_EQ("/tmp/cache.txt", c->File());
    
    EXPECT_EQ(string(), c->Find("key5"));
    c->Insert("key5", "value5");
    EXPECT_EQ(true, c->IsModified());
    EXPECT_EQ("value5", c->Find("key5"));
    c->Save();
    EXPECT_EQ(false, c->IsModified());
    EXPECT_EQ("value5", c->Find("key5"));
    c->Clear();
    EXPECT_EQ(true, c->IsModified());
    EXPECT_EQ(string(), c->Find("key5"));
    
    FileCache<string, string> c2;
    c->Insert("key5", "value5");
    c2 = *c;
    EXPECT_EQ(*c, c2);
    FileCache<string, string> c3(std::move(c2));
    EXPECT_EQ(*c, c3);
    
    c3.Clear();
    c3 = *c;
    EXPECT_EQ(*c, c3);
    
    c2.Insert("key5", "value6");
    EXPECT_NE(*c, c2);
    
    delete c;
}

TEST(FileCache, Operators) 
{
    try 
    {
        FileCache<string, string> c;
        
        ifstream in("/Users/roman/Projects/NLP/GRE/resources/CacheTestFile.txt");
        if (in.is_open())
            in >> c;
        
        stringstream ss;
        ss << c;
        EXPECT_EQ("<cache>\ndefault\n100\nkey1\nvalue1\nkey2\nvalue2\n</cache>\n", ss.str());
        
    } 
    catch (DeserialisationException& de) 
    {
        EXPECT_EQ(true, true);
        cerr << de.what() << endl;
    }
}


